If your homelab has more than a couple of drives, you already know the problem: smartctl works fine, but its output is a wall of raw numbers, smartd emails are cryptic, and nothing tracks how an attribute is trending. That last bit matters most — drives rarely die out of nowhere, they degrade first. This is the setup notes from getting Scrutiny running on Proxmox: a self-hosted dashboard with drive health, historical graphs, and alerts before something actually fails.

I'm using the official Hub-Spoke layout, which is the architecture the Scrutiny maintainers themselves recommend: the web UI and database live safely inside an unprivileged LXC, while a small collector binary runs directly on the Proxmox host — the only place with proper low-level access to the physical disks.

Why Not Just Cram Everything Into One LXC

The tempting shortcut is a single LXC with the disks passed through and everything running inside it. I'd avoid that, for a few reasons:

Hub-Spoke sidesteps all of it:

What You Need

Step 1 — Create the Docker LXC (the Hub)

The Hub runs the web UI and InfluxDB. The quickest way to get a Debian LXC with Docker pre-installed is the Community Scripts helper. From the Proxmox host shell:

bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/docker.sh)"

Note: community scripts run as root on your host. It's worth a quick skim before running one, even a well-known one like this.

During the prompts: pick Advanced mode if you want to tune things, give it 2 cores / 1–2GB RAM / 8–10GB disk (plenty for Scrutiny + InfluxDB), leave it unprivileged, and set a static IP if you can — the collector will need to point at it later.

Enter the container once it's up:

pct enter <CTID>

And sanity-check Docker:

docker --version
docker compose version

Step 2 — Deploy Scrutiny Web + InfluxDB via Docker Compose

Inside the LXC, set up the working directory:

mkdir -p /opt/scrutiny && cd /opt/scrutiny

2a. The config file has to exist first

This tripped me up initially — scrutiny-web needs a config file before its first launch, or it panics trying to build the InfluxDB connection string from nothing:

mkdir -p /opt/scrutiny/config

cat > /opt/scrutiny/config/scrutiny.yaml << 'EOF'
version: 1

web:
  listen:
    port: 8080
    host: 0.0.0.0
  database:
    location: /opt/scrutiny/config/scrutiny.db
  src:
    frontend:
      path: /opt/scrutiny/web

  influxdb:
    host: influxdb
    port: 8086
EOF

2b. docker-compose.yml

This mirrors the project's official hub-only compose example — just the web UI and InfluxDB. The collector doesn't belong in here at all, it lives on the host.

cat > /opt/scrutiny/docker-compose.yml << 'EOF'
services:
  influxdb:
    image: influxdb:2.8
    container_name: scrutiny-influxdb
    restart: unless-stopped
    ports:
      - "8086:8086"
    volumes:
      - ./influxdb:/var/lib/influxdb2
    networks:
      - scrutiny-net
    healthcheck:
      test: ["CMD", "influx", "ping"]
      interval: 10s
      timeout: 5s
      retries: 10

  scrutiny-web:
    image: ghcr.io/analogj/scrutiny:v0.8.6-web
    container_name: scrutiny-web
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - ./config:/opt/scrutiny/config
    depends_on:
      influxdb:
        condition: service_healthy
    networks:
      - scrutiny-net

networks:
  scrutiny-net:
    driver: bridge
EOF

A few details worth flagging, since none of them are obvious from the error messages alone:

2c. Start it

docker compose up -d

Give InfluxDB about 20 seconds to pass its healthcheck, then check the logs:

docker compose logs scrutiny-web

You want to see Successfully connected to scrutiny sqlite db and Database migration completed successfully, with no panics. At that point http://<LXC_IP>:8080 should load — empty, since no collector has reported in yet.

Step 3 — Install the Collector on the Proxmox Host

Back on the Proxmox host (not the LXC), install smartmontools if it isn't already there:

apt install smartmontools -y

Then pull the collector binary — again, v0.8.6 specifically, to match the web image:

mkdir -p /opt/scrutiny/bin /opt/scrutiny/config

wget -O /opt/scrutiny/bin/scrutiny-collector-metrics \
  https://github.com/AnalogJ/scrutiny/releases/download/v0.8.6/scrutiny-collector-metrics-linux-amd64

chmod +x /opt/scrutiny/bin/scrutiny-collector-metrics

Version pinning isn't optional here. Grabbing releases/latest will hand you v0.9.0, and the dashboard will silently stay empty even though the collector runs without errors.

Confirm it:

/opt/scrutiny/bin/scrutiny-collector-metrics --version

Expected: linux.amd64-0.8.6.

3a. collector.yaml — needed for cron to actually work

This is the one that cost me the most time. When cron runs the collector, it uses a stripped-down PATH that doesn't include /usr/sbin, so it can't find smartctl and fails with DependencyMissingError: "smartctl binary is missing" — even though running it manually works perfectly. The fix is pointing at the full binary path explicitly:

cat > /opt/scrutiny/config/collector.yaml << 'EOF'
version: 1
commands:
  metrics_smartctl_bin: /usr/sbin/smartctl
host:
  id: "proxmox-main"
EOF

host.id is just a label — useful once you're feeding more than one host into the same dashboard, which I do below.

3b. Test run

/opt/scrutiny/bin/scrutiny-collector-metrics run \
  --api-endpoint "http://<LXC_IP>:8080"

You should see each drive get detected and posted one by one. Refresh the dashboard — the drives should now be listed.

Step 4 — Schedule It with Cron

Edit the root crontab. The collector needs root to read SMART data. On any host where you log in as a non-root user, use sudo crontab -e — adding the job to a regular user's crontab just fails silently on permissions.

On the Proxmox host (already root):

crontab -e

Add a line for every 30 minutes:

*/30 * * * * /opt/scrutiny/bin/scrutiny-collector-metrics run --api-endpoint "http://<LXC_IP>:8080" >/dev/null 2>&1

On frequency: 30 minutes is a reasonable default — enough resolution for temperature trends without bloating InfluxDB. Go to 15 minutes if you want finer granularity, or hourly if you'd rather keep the database small.

Double-check it saved, and that cron itself is actually running:

crontab -l
systemctl status cron

Troubleshooting Notes

A drive is missing or shows "Unknown"

Usually the collector couldn't auto-detect the device type — common with USB enclosures or SAS/RAID controllers. Give it an explicit hint in collector.yaml:

version: 1
host:
  id: "proxmox-main"
devices:
  - device: /dev/sda
    type: 'sat'
  - device: /dev/sdb
    type: 'sat'
  - device: /dev/nvme0
    type: 'nvme'

Then point the cron entry at that config with --config /opt/scrutiny/config/collector.yaml. Use smartctl --scan to list your actual devices.

NVMe shows no temperature or wear data

This comes down to the smartmontools version on the host — NVMe reports a different attribute schema than SATA, and anything older than 7.0 handles it poorly. Check with smartctl --version.

"Connection refused" from the collector

Almost always a firewall blocking port 8080 between the host and the LXC. Test from the host with curl -v http://<LXC_IP>:8080 and check both the LXC and Proxmox firewall rules if it times out.

Dashboard stays empty even though the collector runs fine

Nine times out of ten this is a version mismatch between the web image and the collector binary. Check both:

# On the LXC
docker compose logs scrutiny-web | grep "linux\|dev-"

# On the Proxmox host
/opt/scrutiny/bin/scrutiny-collector-metrics --version

If they don't match, re-pull the v0.8.6 collector and reset the web container:

docker compose down
sed -i 's|scrutiny:.*-web|scrutiny:v0.8.6-web|' docker-compose.yml
rm -f ./config/scrutiny.db && rm -rf ./influxdb
docker compose up -d

Feeding in Other Hosts

The nice part of Hub-Spoke is that one Hub can take collectors from several machines, not just the Proxmox host it's paired with. Any other Debian-based box gets the same collector binary and steps. The one thing to remember: give each host a unique host.id in its own collector.yaml, or Scrutiny can't tell the drives apart on the dashboard.

Wrapping Up

End state: an unprivileged LXC running the dashboard and InfluxDB, a native collector on the Proxmox host with proper access to the drives, historical trend data. The CPU overhead is negligible, so there's not much reason not to run this once it's set up.